//
//  DSOLinePlot.m
//  Balance
//
//  Created by oracle on 7/19/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "DSOLinePlot.h"
#import "DSOData.h"



@implementation DSOLinePlot


#define oneDayInterval 86400
#define initNumberOfDaysDisplayed 183
#define kCurrentPlot @"SelectedCustomerDSOPlot"
#define kPriorYearPlot @"PriorYearDSOPlot"
#define kDSOForAllPlot @"DSOForAllPlot"
#define kBestPossibleDSOPlot @"BestPossibleDSOPlot"
#define kNoOfCollectorsPlot @"NoOfCollectorsPlot"
#define kRulerPlot @"RulerPlot"
#define kBarPlotSpace @"karPlotSpace"
#define numberOfMarkerPlotSymbols 2
#define kRepeat 20 // repeat count, used for animation
#define kFrameRate 20 // frames per second, used for animation


- (id) init
{
    self = [super init];
    if(self) {
        dailyDSO = nil;
    }
    return self;
}


- (id) initWithOneCustomerData:(NSMutableDictionary *)dsoData 
              allCustomersData:(NSMutableDictionary *)allCustomersDSOData
{
    self = [self init];
    if(self)
    {
        dailyDSO = dsoData;
        dailyKeys = [dailyDSO allKeys];
        totalNoOfDataPoints = [dailyDSO count];
        
        NSDate *today = [[NSDate alloc] init];
        initStartDate = [today dateByAddingTimeInterval:(-1*oneDayInterval*initNumberOfDaysDisplayed)];
        
        
        NSDateFormatter *dsoFormatter = [[NSDateFormatter alloc] init];
        [dsoFormatter setDateFormat:@"yyyyMMdd"];
        initStartDateString = [dsoFormatter stringFromDate:initStartDate];
        
        dailyKeys = [dailyKeys sortedArrayUsingSelector:@selector(compare:)];
        NSInteger initStartIndex = [dailyKeys indexOfObject:initStartDateString];
        
        dailyKeysInRange = [[NSMutableArray alloc] init];
        for (int i=initStartIndex; i <totalNoOfDataPoints; i++){
            [dailyKeysInRange addObject:[dailyKeys objectAtIndex:i]];
        }
        
        noOfDataPointsInRange = [dailyKeysInRange count];
        
        //set up data for allCustomersPlot
        allCustomersDSO  = allCustomersDSOData;
        allCustomersKeys = [allCustomersDSO allKeys];
        allCustomersKeys = [allCustomersKeys sortedArrayUsingSelector:@selector(compare:)];
        allCustomersKeysInRange = [[NSMutableArray alloc] init];
        for (int i=initStartIndex; i <totalNoOfDataPoints; i++){
            [allCustomersKeysInRange addObject:[allCustomersKeys objectAtIndex:i]];
        }
        
        
        //initial position of ruler; 
        rulerIndex = noOfDataPointsInRange -1; //today
        rulerDateString = [dailyKeysInRange objectAtIndex:rulerIndex];    
        
        allCustomersPlotAdded = NO;
        priorPlotAdded = NO;    
        bestPossibleDSOPlotAdded = NO;
        noOfCollectorsPlotAdded = NO;
        
        rangeChanged = NO;
        rulerEnabled = NO;       
    }
    
    return self;
    
}

- (void) renderInLayer:(CPTGraphHostingView *)layerHostingView withTheme:(CPTTheme *)theme
{
    
    CGRect bounds = layerHostingView.bounds;
    
    graph = [[CPTXYGraph alloc] initWithFrame:bounds];
    layerHostingView.hostedGraph = graph;
    layerHostingView.backgroundColor = [UIColor colorWithWhite:0.7f alpha:1.0f]; 
    
    CPTGradient *plotAreaGradient = [CPTGradient gradientWithBeginningColor:[CPTColor colorWithGenericGray:0.9f]endingColor:[CPTColor colorWithGenericGray:0.7f]];
    plotAreaGradient.angle = -90.0;
    graph.plotAreaFrame.plotArea.fill = [CPTFill fillWithGradient:plotAreaGradient]; 
    
    [graph applyTheme:theme];
    
    graph.plotAreaFrame.masksToBorder = NO;
    
    
    CPTMutableTextStyle *blackTextStyle = [[CPTMutableTextStyle alloc] init];
    blackTextStyle.color = [CPTColor colorWithComponentRed:0.2 green:0.2 blue:0.2 alpha:0.82]; //RGB:R51-G51-B51
	blackTextStyle.fontSize = 20.0;
    graph.titleTextStyle = blackTextStyle;
    graph.titleDisplacement = CGPointMake(0.0, 90.0); 
    graph.title = @"Day Sales Outstanding";
    
    
    
    
    // change the chart layer orders so the axis line is on top of the bar in the chart.
    NSArray *chartLayers = [[NSArray alloc] initWithObjects:
                            [NSNumber numberWithInt:CPTGraphLayerTypeAxisLines],
                            [NSNumber numberWithInt:CPTGraphLayerTypeAxisTitles],
                            [NSNumber numberWithInt:CPTGraphLayerTypeAxisLabels], 
                             
                            
                            [NSNumber numberWithInt:CPTGraphLayerTypePlots],
                            [NSNumber numberWithInt:CPTGraphLayerTypeMajorGridLines], 
                            [NSNumber numberWithInt:CPTGraphLayerTypeMinorGridLines],  
                             
                            
                            nil];
    graph.topDownLayerOrder = chartLayers;    
    
    
    // Add plot space for horizontal bar charts
    graph.paddingLeft = 90.0;
	graph.paddingTop = 120.0;//50.0
	graph.paddingRight = 50.0;
	graph.paddingBottom = 50.0;//60.0
    
    // Setup plot space
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    plotSpace.allowsUserInteraction = YES;
    plotSpace.delegate = self;
        
        
    //display last 6 months starting today
    plotSpace.xRange=[CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(oneDayInterval*0) 
                                                  length:CPTDecimalFromFloat(oneDayInterval*initNumberOfDaysDisplayed)];
    plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(100)];
    
    
    
    
    // setup plot space for bar plot
    barPlotSpace = [[CPTXYPlotSpace alloc] init];
    barPlotSpace.identifier = kBarPlotSpace;
    barPlotSpace.delegate = self;
    barPlotSpace.allowsUserInteraction = YES;

    
    barPlotSpace.xRange=[CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(oneDayInterval*0)                                                  
                                                     length:CPTDecimalFromFloat(oneDayInterval*initNumberOfDaysDisplayed)];
    barPlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(400)];

    
    
  
    
    
    
    // Setup grid line style
    CPTMutableLineStyle *majorXGridLineStyle = [CPTMutableLineStyle lineStyle];
    majorXGridLineStyle.lineWidth = 1.0f;
    majorXGridLineStyle.lineColor = [[CPTColor grayColor] colorWithAlphaComponent:0.25f];
    
    CPTMutableLineStyle *majorYGridLineStyle = [CPTMutableLineStyle lineStyle];
    majorYGridLineStyle.lineWidth = 1.0f;
    majorYGridLineStyle.dashPattern =  [NSArray arrayWithObjects:[NSNumber numberWithFloat:5.0f], [NSNumber numberWithFloat:5.0f], nil];
    majorYGridLineStyle.lineColor = [[CPTColor lightGrayColor] colorWithAlphaComponent:0.25];


    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateStyle = kCFDateFormatterShortStyle; // format is mm/dd/yy
    CPTTimeFormatter *timeFormatter =[[CPTTimeFormatter alloc] initWithDateFormatter:dateFormatter];    
    timeFormatter.referenceDate = initStartDate;

    NSArray *yExlusionRanges = [NSArray arrayWithObjects:
                                [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0) length:CPTDecimalFromFloat(0.0)],
                                nil];
    NSNumberFormatter *percentFormatter = [[NSNumberFormatter alloc] init];
    [percentFormatter setNumberStyle:NSNumberFormatterNoStyle];

    
    // Setup x-Axis.
	CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;   
    axisSet.xAxis.majorGridLineStyle = majorXGridLineStyle;
    axisSet.xAxis.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0");    
    //setup x axis label based on weeks; one label per 7 days    
    axisSet.xAxis.majorIntervalLength = CPTDecimalFromFloat(oneDayInterval*30.0);
    axisSet.xAxis.minorTicksPerInterval = 0;    
    axisSet.xAxis.labelFormatter = timeFormatter;
    
    
    // Setup y-Axis.   
    axisSet.yAxis.majorGridLineStyle = majorYGridLineStyle;
    axisSet.yAxis.majorIntervalLength = CPTDecimalFromString(@"20");
    axisSet.yAxis.minorTicksPerInterval = 1;
    axisSet.yAxis.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0");
    axisSet.yAxis.title = @"Days"; 
    axisSet.yAxis.labelExclusionRanges = yExlusionRanges;
    axisSet.yAxis.labelFormatter = percentFormatter;    
    //y-axis stays in fixed position
    axisSet.yAxis.axisConstraints = [CPTConstraints constraintWithLowerOffset:0];
    
    
    // Setup right y-Axis
    
    CPTMutableTextStyle *yLabelTextStyle = [CPTMutableTextStyle textStyle];
    yLabelTextStyle.fontName = @"Helvetica-Bold";
    yLabelTextStyle.color = [CPTColor darkGrayColor];
    yLabelTextStyle.fontSize = 10;
    
    rightY = [[CPTXYAxis alloc] init];
    rightY.coordinate = CPTCoordinateY;
    rightY.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0");
    rightY.plotSpace = barPlotSpace;
    //rightY.majorGridLineStyle = majorYGridLineStyle;
    rightY.majorIntervalLength = CPTDecimalFromString(@"100");
    rightY.majorTickLength = 15.0;
    rightY.minorTickLength = 5.0;
    rightY.minorTicksPerInterval = 1;
    rightY.axisConstraints = [CPTConstraints constraintWithUpperOffset:1];
    rightY.tickDirection = CPTSignNone;
    rightY.titleOffset = -50.0f;
    rightY.labelOffset = -40.0f;
    rightY.labelTextStyle = yLabelTextStyle;
    rightY.title = @"No Of Collectors"; 

    
    [graph addPlotSpace:barPlotSpace]; 
    
    
    
    
    
    // Create 1st plot area in Blue for Current Customer DSO
    dsoCurrentPlot = [[CPTScatterPlot alloc] init];
    dsoCurrentPlot.identifier = kCurrentPlot;
    
    CPTMutableLineStyle *currentLineStyle = [dsoCurrentPlot.dataLineStyle mutableCopy];
	currentLineStyle.lineWidth = 2.f;
    currentLineStyle.lineColor = [CPTColor colorWithComponentRed:0.051 green:0.388 blue:0.894 alpha:1.0]; //RGB: 13-99-228  (blue)
    
    dsoCurrentPlot.dataLineStyle = currentLineStyle;
    dsoCurrentPlot.dataSource = self;  
    
    CPTMutableShadow *blackShadow = [CPTMutableShadow shadow];
    blackShadow.shadowOffset	 = CGSizeMake(0.0, -7.0);
    blackShadow.shadowBlurRadius = 6.0;
    blackShadow.shadowColor		 = [CPTColor blackColor];
    dsoCurrentPlot.shadow= blackShadow;    
    
    [graph addPlot:dsoCurrentPlot];
    
    
    // Create the Prior Year plot
	dsoPriorYearPlot = [[CPTScatterPlot alloc] init];
    dsoPriorYearPlot.identifier = kPriorYearPlot;
    
	CPTMutableLineStyle *priorLineStyle = [dsoCurrentPlot.dataLineStyle mutableCopy];
	priorLineStyle.lineWidth = 2.f;
    priorLineStyle.lineColor = [CPTColor colorWithComponentRed:0.078 green:0.529 blue:0.0 alpha:1.0]; //RGB: 20-135-0  (green)
    dsoPriorYearPlot.dataLineStyle = priorLineStyle;
    dsoPriorYearPlot.dataSource = self;  
    dsoPriorYearPlot.shadow = blackShadow; 
    
    
    // Create the all Customers plot
	dsoDSOForAllPlot = [[CPTScatterPlot alloc] init];
    dsoDSOForAllPlot.identifier = kDSOForAllPlot;
    
	CPTMutableLineStyle *allLineStyle = [dsoCurrentPlot.dataLineStyle mutableCopy];
	allLineStyle.lineWidth = 2.f;
    allLineStyle.lineColor = [CPTColor colorWithComponentRed:0.882 green:0.18 blue:0.137 alpha:1.0];   //RGB: 225-46-35  (orange)
    dsoDSOForAllPlot.dataLineStyle = allLineStyle;
    dsoDSOForAllPlot.dataSource = self;  
    dsoDSOForAllPlot.shadow = blackShadow; 

    
    // Create the best possible dso plot
	dsoBestPossiblePlot = [[CPTScatterPlot alloc] init];
    dsoBestPossiblePlot.identifier = kBestPossibleDSOPlot;
    
	CPTMutableLineStyle *bestPossibleDSOLineStyle = [dsoCurrentPlot.dataLineStyle mutableCopy];
	bestPossibleDSOLineStyle.lineWidth = 2.f;
    bestPossibleDSOLineStyle.lineColor = [CPTColor yellowColor];  
    dsoBestPossiblePlot.dataLineStyle = bestPossibleDSOLineStyle;
    dsoBestPossiblePlot.dataSource = self;  
    dsoBestPossiblePlot.shadow = blackShadow; 

    
    // Create no of collectors plot
    dsoNoOfCollectorsPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor greenColor] horizontalBars:NO];
    dsoNoOfCollectorsPlot.identifier = kNoOfCollectorsPlot;
    dsoNoOfCollectorsPlot.dataSource = self;
    dsoNoOfCollectorsPlot.barWidthsAreInViewCoordinates = YES;
    CGFloat plotWidth = graph.plotAreaFrame.bounds.size.width;
    dsoNoOfCollectorsPlot.barWidth = CPTDecimalFromDouble((plotWidth/noOfDataPointsInRange)*0.5);
    dsoNoOfCollectorsPlot.barWidth = CPTDecimalFromDouble(10);
    dsoNoOfCollectorsPlot.barOffset = CPTDecimalFromDouble(0.25);
    
    CPTMutableLineStyle *barLineStyle = [[CPTMutableLineStyle alloc] init];
    barLineStyle.lineColor = [CPTColor brownColor];
    barLineStyle.lineWidth = 0.5;

    dsoNoOfCollectorsPlot.lineStyle = barLineStyle;

        
    
        
    //create the ruler plot
    rulerPlot =  [[CPTScatterPlot alloc] initWithFrame:CGRectNull];
    rulerPlot.identifier = kRulerPlot;
    rulerPlot.dataSource = self;
    //[self applyRulerPlotColor];
    //[self displayRulerAnnotation];  
    //[graph addPlot:rulerPlot];
    
    
    //add legends
    dsoCurrentPlot.title = @"DSO";
    dsoPriorYearPlot.title = @"Prior Year DSO";
    dsoDSOForAllPlot.title = @"DSO For All";
    dsoBestPossiblePlot.title = @"Best Possible DSO";
    dsoNoOfCollectorsPlot.title = @"No Of Collectors";
    
    CPTLegend *lineLegend = [CPTLegend legendWithPlots:[NSArray arrayWithObjects:dsoCurrentPlot, dsoDSOForAllPlot, dsoPriorYearPlot, dsoBestPossiblePlot, dsoNoOfCollectorsPlot, nil]]; 
    lineLegend.numberOfColumns = 5;
    graph.legend= lineLegend;
    graph.legend.fill = [CPTFill fillWithColor:[CPTColor clearColor]];
    graph.legend.cornerRadius = 5.0;
    graph.legend.swatchSize = CGSizeMake(10.0, 10.0);
    graph.legendAnchor = CPTRectAnchorTop;  //CPTRectAnchorRight
    graph.legendDisplacement = CGPointMake(0.0, -80.0);  //position of the legend
    
    CPTMutableTextStyle *legendTextStyle = [[CPTMutableTextStyle alloc] init];
	legendTextStyle.color = [CPTColor darkGrayColor];
	legendTextStyle.fontSize = 11.0;
    legendTextStyle.fontName = @"Helvetica-Bold";
    graph.legend.textStyle = legendTextStyle;
        
}


-(void)respondToRangeChangeFromDate:(NSString *)newFromDateString toDate:(NSString *)newToDateString
{
    
    NSInteger startIndex = [dailyKeys indexOfObject:newFromDateString];
    NSInteger endIndex = [dailyKeys indexOfObject:newToDateString];
    //NSLog(@"newFromDateString=%@,startIndex=%i,newToDateString=%@,endIndex=%i",newFromDateString,startIndex,newToDateString,endIndex);
    
    int NoOfDaysInRange = endIndex - startIndex +1;;
    
    if (NoOfDaysInRange != noOfDataPointsInRange)
        rangeChanged = YES;
    
    int gap = 1;
    if (NoOfDaysInRange > initNumberOfDaysDisplayed*1.5) {
        gap = (NoOfDaysInRange/initNumberOfDaysDisplayed)+1;
    };
    
    
    //for animation. Copy dailyKeysInRange as it will be changed soon.
    animationStartDailyKeys = [NSMutableArray arrayWithCapacity:2000]; 
    for (int s=0;s<noOfDataPointsInRange;s++){
        [animationStartDailyKeys addObject:[dailyKeysInRange objectAtIndex:s]];
    };
    
    
    //refresh the current plot for the new range         
    NSMutableArray *displayDailyKeys  = [NSMutableArray arrayWithCapacity:5000];
    
    for (int idx= startIndex; idx < endIndex+1; idx++){
        [displayDailyKeys addObject:[dailyKeys objectAtIndex:idx]];
    };
    
    if (rulerEnabled){ 
        rulerIndex = (rulerIndex * [displayDailyKeys count]) / noOfDataPointsInRange;
    }
    
    dailyKeysInRange = displayDailyKeys;
    noOfDataPointsInRange = [dailyKeysInRange count];
    //NSLog(@"NoOfDaysInRange=%i, NoOfDataPointsInRange=%i",NoOfDaysInRange,NoOfDataPointsInRange);
    
    //set up animation data
    [self prepareAnimationData];
    
    if (rulerEnabled){
        rulerDateString = [dailyKeysInRange objectAtIndex:rulerIndex];
        [self displayRulerAnnotation];
    }
    
    
    
    //-----------------------------------------------------
    //refresh the all collectors plot for the new range         
    NSMutableArray *displayAllCollectorsKeysInRange  = [NSMutableArray arrayWithCapacity:5000];
    for (int idx= startIndex; idx < endIndex+1; idx++){
        [displayAllCollectorsKeysInRange addObject:[dailyKeys objectAtIndex:idx]];
    };
    
    allCustomersKeysInRange = displayAllCollectorsKeysInRange;
    
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(oneDayInterval*0) 
                                                    length:CPTDecimalFromFloat(oneDayInterval* (NoOfDaysInRange-1))];
    
    
    barPlotSpace.xRange = plotSpace.xRange;
    
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis *x = axisSet.xAxis;
    
    x.majorIntervalLength = CPTDecimalFromFloat(oneDayInterval*30.0 * gap);
    
    NSDateFormatter *fromDateFormatter = [[NSDateFormatter alloc] init];
    [fromDateFormatter setDateFormat:@"yyyyMMdd"];
    NSDate *newFromDate = [fromDateFormatter dateFromString:newFromDateString]; 
    NSDate *refDate = newFromDate;   
    
    NSDateFormatter *refDateFormatter = [[NSDateFormatter alloc] init];
    [refDateFormatter setDateFormat:@"MM/dd/yy"];
    
    CPTTimeFormatter *timeFormatter =[[CPTTimeFormatter alloc] initWithDateFormatter:refDateFormatter];
    timeFormatter.referenceDate = refDate;
    x.labelFormatter = timeFormatter;
    
    //[graph reloadData];
    CGFloat plotWidth = graph.plotAreaFrame.plotArea.bounds.size.width;
    dsoNoOfCollectorsPlot.barWidth = CPTDecimalFromDouble((plotWidth/noOfDataPointsInRange)*0.5);

    
    //animation
    dataTimer = [NSTimer timerWithTimeInterval:0.5/kFrameRate
                                        target:self
                                      selector:@selector(newData:)
                                      userInfo:nil
                                       repeats:YES];
	[[NSRunLoop mainRunLoop] addTimer:dataTimer forMode:NSDefaultRunLoopMode];
    
    [rulerPlot reloadData];
    
};

-(void)prepareAnimationData{
    
    //set up unit of change for animation
    animationUnit = [NSMutableArray arrayWithCapacity:2000]; 
    
    for (int r=0;r<noOfDataPointsInRange;r++){
        
        DSOData *startData;
        DSOData *endData;
        DSOData *startDataAll;
        DSOData *endDataAll;
        float newCurrent, newCurrentAll, newCurrentPrior, newCurrentBestPossible, newCurrentNoOf;
        float oldCurrent, oldCurrentAll, oldCurrentPrior, oldCurrentBestPossible, oldCurrentNoOf;
        float diffCurrent, diffCurrentAll, diffCurrentPrior, diffCurrentBestPossible, diffCurrentNoOf;
        float unitCurrent, unitCurrentAll, unitCurrentPrior, unitCurrentBestPossible, unitCurrentNoOf;
        
        if (r < [animationStartDailyKeys count]){
            startData = [dailyDSO objectForKey:[animationStartDailyKeys objectAtIndex:r]];
            startDataAll = [allCustomersDSO objectForKey:[animationStartDailyKeys objectAtIndex:r]];            
            //NSLog(@"2r=%i,startData",r);
        }
        else{ 
            startData = nil;
            startDataAll = nil;
        }
        
        if (r < [dailyKeysInRange count]){
            endData = [dailyDSO objectForKey:[dailyKeysInRange objectAtIndex:r]];
            endDataAll = [allCustomersDSO objectForKey:[dailyKeysInRange objectAtIndex:r]];
            //NSLog(@"3r=%i,endData",r);
        }
        else{
            endData = nil;
            endDataAll = nil;
        }
        
        
        
        NSMutableDictionary *unitDict = [[NSMutableDictionary alloc] init];
        if (endData){
            newCurrent = [endData.currentValue floatValue];
            newCurrentPrior = [endData.priorYearValue floatValue];
            newCurrentAll = [endDataAll.currentValue floatValue];
            newCurrentBestPossible = [endData.bestPossibleDSOValue floatValue];
            newCurrentNoOf = [endData.noOfCollectorsValue floatValue];
        } else{  
            newCurrent = 0;
            newCurrentPrior = 0;
            newCurrentAll = 0;
            newCurrentBestPossible = 0;
            newCurrentNoOf = 0;
        }
        if (startData){
            oldCurrent = [startData.currentValue floatValue];
            oldCurrentPrior = [startData.priorYearValue floatValue];
            oldCurrentAll = [startDataAll.currentValue floatValue];
            oldCurrentBestPossible = [startData.bestPossibleDSOValue floatValue];
            oldCurrentNoOf = [startData.noOfCollectorsValue floatValue];

        } else{  
            oldCurrent = 0;
            oldCurrentPrior = 0;
            oldCurrentAll = 0;
            oldCurrentBestPossible = 0;
            oldCurrentNoOf = 0;
        }
        
        //if ((newPercent != 0) && (oldPercent != 0))   
        if ((endData) && (startData))
            diffCurrent = newCurrent - oldCurrent;
        else diffCurrent = 0;
        //if ((newPercentPrior != 0) && (oldPercentPrior != 0))
        if ((endData) && (startData))
            diffCurrentPrior = newCurrentPrior - oldCurrentPrior;
        else diffCurrentPrior = 0;
        //if ((newPercentAll != 0) && (oldPercentAll != 0))
        if ((endData) && (startData))
            diffCurrentAll = newCurrentAll - oldCurrentAll;
        else diffCurrentAll = 0;
        
        if ((endData) && (startData))
            diffCurrentBestPossible = newCurrentBestPossible - oldCurrentBestPossible;
        else diffCurrentBestPossible = 0;

        if ((endData) && (startData))
            diffCurrentNoOf = newCurrentNoOf - oldCurrentNoOf;
        else diffCurrentNoOf = 0;

        
        
        unitCurrent = diffCurrent / kRepeat;
        unitCurrentPrior = diffCurrentPrior / kRepeat;
        unitCurrentAll = diffCurrentAll / kRepeat;
        unitCurrentBestPossible = diffCurrentBestPossible/ kRepeat;
        unitCurrentNoOf = diffCurrentNoOf/kRepeat;
        
        [unitDict setObject:[NSNumber numberWithFloat:unitCurrent] forKey:@"current"];
        [unitDict setObject:[NSNumber numberWithFloat:unitCurrentPrior] forKey:@"prior"];
        [unitDict setObject:[NSNumber numberWithFloat:unitCurrentAll] forKey:@"all"];
        [unitDict setObject:[NSNumber numberWithFloat:unitCurrentBestPossible] forKey:@"bestPossible"];
        [unitDict setObject:[NSNumber numberWithFloat:unitCurrentNoOf] forKey:@"noOfCollectors"];
        
        [animationUnit addObject:unitDict];
        
    }
    
}

-(void)newData:(NSTimer *)theTimer
{
     
    
    [dsoCurrentPlot reloadDataInIndexRange:NSMakeRange(0,noOfDataPointsInRange)];
    [dsoPriorYearPlot reloadDataInIndexRange:NSMakeRange(0,noOfDataPointsInRange)];
    [dsoDSOForAllPlot reloadDataInIndexRange:NSMakeRange(0,noOfDataPointsInRange)];
    [dsoBestPossiblePlot reloadDataInIndexRange:NSMakeRange(0,noOfDataPointsInRange)];
    [dsoNoOfCollectorsPlot reloadDataInIndexRange:NSMakeRange(0,noOfDataPointsInRange)];
    
    
    timerCount++;
    if (timerCount >= kRepeat) {
        [theTimer invalidate];
        timerCount = 0;
    }
    
}

- (void) applyRulerPlotColor
{
    CPTMutableLineStyle *rulerLineStyle = [CPTMutableLineStyle lineStyle];
    rulerLineStyle.dashPattern = [NSArray arrayWithObjects:[NSNumber numberWithFloat:4.0f],nil];
    rulerLineStyle.lineColor = [CPTColor cyanColor];
    rulerLineStyle.lineWidth = 2.0f;
    rulerPlot.dataLineStyle = rulerLineStyle;
}

- (void) highlightRulerPlotColor
{
    CPTMutableLineStyle *selectedRulerLineStyle = [CPTMutableLineStyle lineStyle];
    selectedRulerLineStyle.dashPattern = [NSArray arrayWithObjects:[NSNumber numberWithFloat:4.0f],nil];
    selectedRulerLineStyle.lineColor = [CPTColor yellowColor];
    selectedRulerLineStyle.lineWidth = 2.0f;
    rulerPlot.dataLineStyle = selectedRulerLineStyle;
}

- (void) removeRulerAnnotation
{
    if(symbolTextAnnotation)
    {
        [graph.plotAreaFrame.plotArea removeAnnotation:symbolTextAnnotation];
        symbolTextAnnotation = nil;
    }
}

-(void) displayRulerAnnotation
{
    [self removeRulerAnnotation];
    
    //setup a style for annotation
    CPTMutableTextStyle *hitAnnotationTextStyle = [CPTMutableTextStyle textStyle];
    hitAnnotationTextStyle.color = [CPTColor cyanColor];
    hitAnnotationTextStyle.fontSize = 13.0f;
    hitAnnotationTextStyle.fontName = @"Helvetica-Bold";
    
    NSString *refDateString = [dailyKeysInRange objectAtIndex:0];
    DSOData *refData = [dailyDSO objectForKey:refDateString];
    DSOData *rulerData = [dailyDSO objectForKey:rulerDateString];
    
    NSArray *anchorPoint = [NSArray arrayWithObjects:[NSNumber numberWithFloat:(refData.timeIntervalSinceToday - rulerData.timeIntervalSinceToday)],[NSNumber numberWithInt:110],nil];
    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"MM/dd/yyyy"];
    NSString *asOfDateString = [dateFormat stringFromDate:rulerData.date];
    NSString *formattedCurrent = [NSString stringWithFormat:@"%.02f", [rulerData.currentValue floatValue]];
    NSString *rulerString = [NSString stringWithFormat:@" %@ - %@ \n", formattedCurrent, asOfDateString];
    
    CPTTextLayer *textLayer = [[CPTTextLayer alloc] initWithText:rulerString style:hitAnnotationTextStyle];
    
    symbolTextAnnotation = [[CPTPlotSpaceAnnotation alloc] initWithPlotSpace:graph.defaultPlotSpace anchorPlotPoint:anchorPoint];
    textLayer.backgroundColor = [UIColor blackColor].CGColor;
    textLayer.frame = CGRectMake(0, 0, 120, 18 );
    
    symbolTextAnnotation.contentLayer = textLayer;
    symbolTextAnnotation.displacement = CGPointMake(0.0f, -35.0f);
    
    [graph.plotAreaFrame.plotArea addAnnotation:symbolTextAnnotation];
    
    
}


- (void) removePlot:(NSString *)plotIdentifier
{
    if ([plotIdentifier isEqualToString:kPriorYearPlot]) 
    {
        [graph removePlot:dsoPriorYearPlot];
        priorPlotAdded = NO;        
    } 
    else if ([plotIdentifier isEqualToString:kDSOForAllPlot])
    {
        [graph removePlot:dsoDSOForAllPlot];
        allCustomersPlotAdded = NO;                
    }     
    else if ([plotIdentifier isEqualToString:kBestPossibleDSOPlot])
    {
        [graph removePlot:dsoBestPossiblePlot];
        bestPossibleDSOPlotAdded = NO;
    }
    else if ([plotIdentifier isEqualToString:kNoOfCollectorsPlot])
    {
        NSMutableArray *newAxes = [graph.axisSet.axes mutableCopy];
        [newAxes removeObject:rightY];
        //[newAxes addObject:rightY];
        graph.axisSet.axes = newAxes;

        [graph removePlot:dsoNoOfCollectorsPlot];
        noOfCollectorsPlotAdded = NO;
    }

}


- (void) addPlot:(NSString *)plotIdentifier
{
    if ([plotIdentifier isEqualToString:kPriorYearPlot]) 
    {
        [graph addPlot:dsoPriorYearPlot];
        priorPlotAdded = YES;        
    } 
    else if ([plotIdentifier isEqualToString:kDSOForAllPlot])
    {
        [graph addPlot:dsoDSOForAllPlot];
        allCustomersPlotAdded = YES;                
    }    
    else if ([plotIdentifier isEqualToString:kBestPossibleDSOPlot])
    {
        [graph addPlot:dsoBestPossiblePlot];
        bestPossibleDSOPlotAdded = YES;
    }
    else if ([plotIdentifier isEqualToString:kNoOfCollectorsPlot])
    {
        NSMutableArray *newAxes = [graph.axisSet.axes mutableCopy];
        [newAxes addObject:rightY];
        graph.axisSet.axes = newAxes;

        CGFloat plotWidth = graph.plotAreaFrame.plotArea.bounds.size.width;
        dsoNoOfCollectorsPlot.barWidth = CPTDecimalFromDouble((plotWidth/noOfDataPointsInRange)*0.5);
        [graph addPlot:dsoNoOfCollectorsPlot toPlotSpace:barPlotSpace];
        noOfCollectorsPlotAdded = YES;
    }

}



# pragma mark - CPTPlotDataSource Delegate 

- (NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
    if ([(NSString *)plot.identifier isEqualToString:kRulerPlot])
    {
        return numberOfMarkerPlotSymbols;
    }
    else 
    {
        return noOfDataPointsInRange;
    }
}



- (NSNumber *)numberForPlot:(CPTPlot *)plot 
                      field:(NSUInteger)fieldEnum 
                recordIndex:(NSUInteger)index
{
    NSNumber *num;
    
    DSOData *startData, *endData, *indexData;
    NSString *refDateString = [dailyKeysInRange objectAtIndex:0];
    DSOData *refData = [dailyDSO objectForKey:refDateString];
    NSString *indexDateString = [dailyKeysInRange objectAtIndex:index];
    endData = [dailyDSO objectForKey:indexDateString];
    
    if (index < [animationStartDailyKeys count]){
        NSString *startDateString = [animationStartDailyKeys objectAtIndex:index];
        startData = [dailyDSO objectForKey: startDateString];
    } else startData = nil;
    
    if (startData)
        indexData = startData;
    else indexData = endData;
    
    NSDictionary *unitDict = [animationUnit objectAtIndex:index];
    
    if([(NSString *)plot.identifier isEqualToString:kCurrentPlot])
    {
        if(fieldEnum == CPTScatterPlotFieldY)
        {
            float currentDSO = [indexData.currentValue floatValue];
            NSNumber *unitCurrent = [unitDict objectForKey:@"current"];
            float current = 
            currentDSO + [unitCurrent floatValue] * (timerCount+1);
            num = [NSNumber numberWithFloat:current];
        }
        else
        {
            num = [NSNumber numberWithFloat:(refData.timeIntervalSinceToday - endData.timeIntervalSinceToday)];
        }
    }
    
    if([(NSString *)plot.identifier isEqualToString:kPriorYearPlot])
    {                
        if(fieldEnum == CPTScatterPlotFieldY)
        {
            float currentPriorYear = [indexData.priorYearValue floatValue];
            NSNumber *unitPriorYear = [unitDict objectForKey:@"prior"];
            float current = 
            currentPriorYear + [unitPriorYear floatValue] * (timerCount+1);
            num = [NSNumber numberWithFloat:current];
        }
        else
        {
            num = [NSNumber numberWithFloat:(refData.timeIntervalSinceToday - endData.timeIntervalSinceToday)];
        }

    }
    
    if ([(NSString *)plot.identifier isEqualToString:kBestPossibleDSOPlot])
    {
        
        
        if(fieldEnum == CPTScatterPlotFieldY)
        {
            float currentBestPossible = [indexData.bestPossibleDSOValue floatValue];
            NSNumber *unitBestPossible = [unitDict objectForKey:@"bestPossible"];
            float current = 
            currentBestPossible + [unitBestPossible floatValue] * (timerCount+1);
            num = [NSNumber numberWithFloat:current];
        }
        else
        {
            num = [NSNumber numberWithFloat:(refData.timeIntervalSinceToday - endData.timeIntervalSinceToday)];
        }

    }
    
    if ([(NSString *)plot.identifier isEqualToString:kDSOForAllPlot])
    {
        
        endData = [allCustomersDSO objectForKey:indexDateString];
        startData = nil;
        if (index < [animationStartDailyKeys count]){
            NSString *startDateString = [animationStartDailyKeys objectAtIndex:index];
            startData = [allCustomersDSO objectForKey: startDateString];
        } else startData = nil;
        
        if (startData)
            indexData = startData;
        else indexData = endData;
        
        
        if(fieldEnum == CPTScatterPlotFieldY)
        {
            float currentDSOAll = [indexData.currentValue floatValue];
            NSNumber *unitCurrent = [unitDict objectForKey:@"all"];
            float current = 
            currentDSOAll + [unitCurrent floatValue] * (timerCount+1);
            num = [NSNumber numberWithFloat:current];
            
        }
        else
        {
            num = [NSNumber numberWithFloat:(refData.timeIntervalSinceToday - endData.timeIntervalSinceToday)];
        }
        
    }

    
    
    if ([(NSString *)plot.identifier isEqualToString:kNoOfCollectorsPlot])
    {
        
        if(fieldEnum == CPTBarPlotFieldBarTip) 
        {
            float currentNoOfCollectors = [indexData.noOfCollectorsValue floatValue];
            NSNumber *unitNoOfCollectors = [unitDict objectForKey:@"noOfCollectors"];
            float current = 
            currentNoOfCollectors + [unitNoOfCollectors floatValue] * (timerCount+1);
            num = [NSNumber numberWithFloat:current];
        }
        else
        {
            num = [NSNumber numberWithFloat:(refData.timeIntervalSinceToday - endData.timeIntervalSinceToday)];
        }
        
    }

    
    if ([(NSString *)plot.identifier isEqualToString:kRulerPlot]){
        
        if ( fieldEnum == CPTScatterPlotFieldY ) 
        {
            switch (index) {
                case 0:
                    num = [NSNumber numberWithInt:0];
                    break; 
                case 1:
                    num = [NSNumber numberWithInt:100];
                    break;    
                default:
                    num = [NSNumber numberWithInt:0];
                    break;
            }
        } 
        else if (fieldEnum == CPTScatterPlotFieldX) 
        {   
            
            NSString *refDateString = [dailyKeysInRange objectAtIndex:0];
            DSOData *refData = [dailyDSO objectForKey:refDateString];
            DSOData *rulerData = [dailyDSO objectForKey:rulerDateString];
            
            num=[NSNumber numberWithFloat: (refData.timeIntervalSinceToday - rulerData.timeIntervalSinceToday)];
        }
    }

    //TO DO for all the plots
    
    
return num;
    
    
    
    
}


#pragma mark - CPTPlotSpace Delegate Methods


- (CPTPlotRange *) plotSpace:(CPTPlotSpace *)space willChangePlotRangeTo:(CPTPlotRange *)newRange forCoordinate:(CPTCoordinate)coordinate
{
    if(coordinate == CPTCoordinateY) {
        return ((CPTXYPlotSpace *)space).yRange;
        
    }
    else {
        return ((CPTXYPlotSpace *)space).xRange;
    }
}

- (BOOL) plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDraggedEvent:(id)event atPoint:(CGPoint)point
{
    if(![space.identifier isEqual:kBarPlotSpace])
    {
        if(!rulerEnabled)
        {
            [self applyRulerPlotColor];
            [self displayRulerAnnotation];
            rulerEnabled = YES;
            [graph addPlot:rulerPlot];
            [rulerPlot reloadData];
        }
        
           
        CGPoint pointInPlotArea = [graph convertPoint:point toLayer:graph.plotAreaFrame];
        NSDecimal newPoint[2];
        [graph.defaultPlotSpace plotPoint:newPoint forPlotAreaViewPoint:pointInPlotArea];
        NSDecimalRound(&newPoint[0], &newPoint[0], 0, NSRoundPlain);
        
        int x = [[NSDecimalNumber decimalNumberWithDecimal:newPoint[0]] intValue];
        
        if(!rulerEnabled)
        {
            [self applyRulerPlotColor];
            [self displayRulerAnnotation];
            rulerEnabled = YES;
            [graph addPlot:rulerPlot];
            [rulerPlot reloadData];
        }
        
        int maxRange = noOfDataPointsInRange;
        
        int totalRange = oneDayInterval*maxRange;
        
        if(x>totalRange)
        {
            if(rulerIndex <= (noOfDataPointsInRange -2))
            {
                rulerIndex = rulerIndex +1;
            }
        } else if (x<0) {
            if(rulerIndex >=1 )
            {
                rulerIndex = rulerIndex -1;
            }
        } else {
            x=x/oneDayInterval;
            if(x<noOfDataPointsInRange)
            {
                rulerIndex = x;
            }
        }
        
        
        selectedDateString = [dailyKeysInRange objectAtIndex:rulerIndex];
        rulerDateString = selectedDateString;
        
        [self displayRulerAnnotation];
        [rulerPlot reloadData];
        
        return YES;
    }
    else
    {
        return NO;
    }

 
}

- (BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDownEvent:(id)event 
          atPoint:(CGPoint)point
{
    if(![space.identifier isEqual:kBarPlotSpace])
    {
        // Convert the touch point to plot area frame location
        CGPoint pointInPlotArea = [graph convertPoint:point toLayer:graph.plotAreaFrame];
        NSDecimal newPoint[2];
        [graph.defaultPlotSpace plotPoint:newPoint forPlotAreaViewPoint:pointInPlotArea];
        NSDecimalRound(&newPoint[0], &newPoint[0], 0, NSRoundPlain);
        
        int x = [[NSDecimalNumber decimalNumberWithDecimal:newPoint[0]] intValue];
        
        x =  x/oneDayInterval;
        
       
        if (rulerEnabled){
            [graph removePlot:rulerPlot];
            [self removeRulerAnnotation];
            rulerEnabled = NO;
        } else{
            rulerIndex = x;
            rulerDateString = [dailyKeysInRange objectAtIndex:x];
            [self applyRulerPlotColor];
            [self displayRulerAnnotation]; 
            rulerEnabled = YES;
            [graph addPlot:rulerPlot];
            [rulerPlot reloadData];
            
            
        }   
    
    
        return YES;
    }
    else {
        return NO;
    }
}

- (BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceUpEvent:(id)event atPoint:(CGPoint)point
{
    
    if(![space.identifier isEqual:kBarPlotSpace])
    {
        // Convert the touch point to plot area frame location
        CGPoint pointInPlotArea = [graph convertPoint:point toLayer:graph.plotAreaFrame];
        NSDecimal newPoint[2];
        [graph.defaultPlotSpace plotPoint:newPoint forPlotAreaViewPoint:pointInPlotArea];
        NSDecimalRound(&newPoint[0], &newPoint[0], 0, NSRoundPlain);
        
        int x = [[NSDecimalNumber decimalNumberWithDecimal:newPoint[0]] intValue];
        int maxRange = initNumberOfDaysDisplayed;
        
        if ((rangeChanged) && (noOfDataPointsInRange > initNumberOfDaysDisplayed)) 
            maxRange = noOfDataPointsInRange; 
        
        int totalRange = oneDayInterval*maxRange; 
        
        if ((x > totalRange) || ( x < 0)){
            return NO;
        }
        else {
            
            int totalRange = oneDayInterval*maxRange;
            x =  x/(totalRange/noOfDataPointsInRange);
            
            selectedDateString = [dailyKeysInRange objectAtIndex:x];
            
            rulerDateString = selectedDateString;
            rulerIndex = x;
            [self applyRulerPlotColor];
            return YES;
        };
    }
    else {
        return NO;
    }
}


























@end
